package synchronicity.agent;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

import synchronicity.host.SchedulerHost;
import synchronicity.io.Streamable;

/**
 * An Agent is basically a Visitor that marks which
 * hosts it has already visited.
 * It can be serialized using the Streamable interface
 */
public abstract class Agent implements Streamable {
	private Vector hostsVisited;

	public Agent() {
		hostsVisited = new Vector();
	}

	public void visit(SchedulerHost host) {
		if (!hostsVisited.contains(host.getHostIdentifier()))
			hostsVisited.addElement(host.getHostIdentifier());
		else {
			System.err.println(this.toString() + " visiting host "
					+ host.getHostIdentifier() + " multiple times! ");
		}
		visitHost(host);
	}

	protected abstract void visitHost(SchedulerHost host);

	public String[] getHostsVisited() {
		String[] result = new String[hostsVisited.size()];
		for (int ii = 0; ii < result.length; ii++) {
			result[ii] = (String) hostsVisited.elementAt(ii);
		}
		return result;
	}

	public String toString() {
		String result = getType() + " hosts visited [";
		if (hostsVisited != null) {
			for (int ii = 0; ii < hostsVisited.size(); ii++) {
				result += hostsVisited.elementAt(ii);
				if (ii < hostsVisited.size() - 1) {
					result += ", ";
				}
			}
		} else {
			result += "null";
		}
		result += "]";
		return result;
	}

	public void read(DataInputStream stream) throws IOException {
		hostsVisited = new Vector();
		int size = stream.readInt();
		for (int ii = 0; ii < size; ii++) {
			String host = stream.readUTF();
			hostsVisited.addElement(host);
		}
		readAgent(stream);
	}

	protected abstract void readAgent(DataInputStream stream)
			throws IOException;

	public void write(DataOutputStream stream) throws IOException {
		stream.writeInt(hostsVisited.size());
		for (int ii = 0; ii < hostsVisited.size(); ii++)
			stream.writeUTF((String) hostsVisited.elementAt(ii));
		writeAgent(stream);
	}

	protected abstract void writeAgent(DataOutputStream stream)
			throws IOException;

	public abstract String getType();
}
